﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Web;
using System.Web.Services;
using CustomerContactSystem.Core.AppServices.FixYourStreet;
using CustomerContactSystem.Core.DataAccess.nHibernate;
using CustomerContactSystem.Core.Infrastructure.Email;
using CustomerContactSystem.Core.Model;
using StructureMap;

namespace CustomerContactSystem.WebForms.Services {
    /// <summary>
    /// Summary description for CustomerContactSystemService - Please update the namespace for your authority
    /// </summary>
    [WebService(Namespace = "http://www.soutdublin.ie/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    // [System.Web.Script.Services.ScriptService]
    public class CustomerContactSystemService : WebService { 
        [WebMethod]
        public void SendPendingEmails() {
            var emailRepository = new NhibernateRepository<EnquiryEmail>(Global.SessionFactory.GetCurrentSession());
            var emailService = ObjectFactory.GetInstance<IEmailService>();
            //var emailService = new SmtpEmailService(ConfigurationManager.AppSettings["SmptServerAddress"]);

            var unsentEmails = emailRepository.QueryOver().Where(e => !e.HasBeenSent).OrderBy(e => e.DateCreated).Asc.List();

            foreach (var enqEmail in unsentEmails) {
                emailService.SendEmail(enqEmail.ToEmail());
                enqEmail.HasBeenSent = true;
                enqEmail.DateSent = DateTime.Now;
                emailRepository.Update(enqEmail);
            }
        }

        [WebMethod]
        public void ImportNewFixYourStreetIncidents() {
            var enquiryRepository = new NhibernateRepository<Enquiry>(Global.SessionFactory.GetCurrentSession());
            var classification = GetDefaultClassification();
            var source = GetDefaultSource();
            var defaultSubmitter = GetDefaultSubmitter();
            var defaultReferee = GetDefaultReferee();
            var categoryMatchUps = GetCategoryMatchUps();
            var refereeMatchups = GetCategoryRefereeMatchUps();

            var fixYourStreetService = new FixYourStreetService
                {
                    FysUrl = ConfigurationManager.AppSettings["FixYourStreetUrl"],
                    FysFolder = ConfigurationManager.AppSettings["FixYourStreetApiFolder"],
                    FysApiVersion = ConfigurationManager.AppSettings["FixYourStreetApiVersion"]
                };

            var incidentIds = enquiryRepository.QueryOver().Select(e => e.FixYourStreetId).List<int>();

            var fysEnquiries = fixYourStreetService.GetLatestIncidents(0);

            foreach (var fysEnquiry in fysEnquiries) {
                if (!incidentIds.Contains(fysEnquiry.Id)) {
                    var enquiries = fixYourStreetService.MapFixYourStreetIncidentToEnquiry(fysEnquiry, categoryMatchUps,
                                                                                         classification, source,
                                                                                         defaultSubmitter);

                    foreach (var enquiry in enquiries) {
                        var fysCategoryId = GetFysCategoryId(categoryMatchUps, enquiry.Category.Id);
                        enquiryRepository.Add(enquiry);
                        enquiry.AddFixYourStreetStatusUpdate("O");
                        enquiry.AddHistory(enquiry.DateOfEnquiry, enquiry.CurrentStatus);
                        var viewUrl = ConfigurationManager.AppSettings["SiteRoot"] + "Enquiries/View.aspx?id=" + enquiry.Id;
                        var referee = defaultReferee;
                        if (refereeMatchups.ContainsKey(fysCategoryId)) {
                            referee = refereeMatchups[fysCategoryId];
                        }
                        enquiry.Refer(defaultSubmitter, referee, viewUrl);

                        enquiryRepository.Update(enquiry);
                    }  
                }
            }
        }

        [WebMethod]
        public void ImportNewFixYourStreetComments() {
            var defaultUser = GetDefaultUser();
            var rootUrl = ConfigurationManager.AppSettings["SiteRoot"] + "Enquiries/View.aspx?id=";
            var enquiryRepository = new NhibernateRepository<Enquiry>(Global.SessionFactory.GetCurrentSession());
            var commentRepository = new NhibernateRepository<EnquiryComment>(Global.SessionFactory.GetCurrentSession());
            var commentIds = commentRepository.QueryOver().Select(c => c.FixYourStreetCommentId).List<int>();

            var fixYourStreetService = new FixYourStreetService
            {
                FysUrl = ConfigurationManager.AppSettings["FixYourStreetUrl"],
                FysFolder = ConfigurationManager.AppSettings["FixYourStreetApiFolder"],
                FysApiVersion = ConfigurationManager.AppSettings["FixYourStreetApiVersion"]
            };

            var fysComments = fixYourStreetService.GetLatestComments(0);

            foreach (var fixYourStreetComment in fysComments) {
                if (fixYourStreetComment.CommentIsActive && !commentIds.Contains(fixYourStreetComment.Id)) {
                    var fysComment = fixYourStreetComment;
                    var commentText = "Submitted to Fix Your Street by " + fysComment.CommentAuthor + " on ";
                    commentText += fysComment.CommentDate.ToString("dd/MM/yyyy HH:mm") + "/n/n";
                    commentText += fysComment.CommentDescription;

                    var enquiries = enquiryRepository.QueryOver().Where(e => e.FixYourStreetId == fysComment.IncidentId).List();

                    foreach (var enquiry in enquiries) {
                        var enqUrl = rootUrl + enquiry.Id;
                        var currentlyWith = enquiry.CurrentReferral != null ? enquiry.CurrentReferral.CurrentlyReferredTo : null;
                        var comment = enquiry.AddComment(defaultUser, commentText, false, false, false, currentlyWith, enqUrl);
                        comment.FixYourStreetCommentId = fysComment.Id;
                        enquiryRepository.Update(enquiry);
                    } 
                }
            }
        }

        [WebMethod]
        public void ExportPendingComments() {
            var commentRepository = new NhibernateRepository<EnquiryComment>(Global.SessionFactory.GetCurrentSession());
            var author = ConfigurationManager.AppSettings["OrganisationName"] + " Agent";

            var fixYourStreetService = new FixYourStreetService
            {
                FysUrl = ConfigurationManager.AppSettings["FixYourStreetUrl"],
                FysFolder = ConfigurationManager.AppSettings["FixYourStreetApiFolder"],
                FysApiVersion = ConfigurationManager.AppSettings["FixYourStreetApiVersion"]
            };

            var pendingComments = commentRepository.QueryOver()
                .Where(c => c.SentToFixYourStreet && c.FixYourStreetCommentId == 0)
                .OrderBy(c => c.CommentDate).Asc
                .List();

            foreach (var pendingComment in pendingComments) {
                var commentContent = HttpUtility.UrlEncode(HttpUtility.HtmlDecode(pendingComment.Comment));
                pendingComment.FixYourStreetCommentId = fixYourStreetService.SubmitComment(pendingComment.Enquiry.FixYourStreetId, author, commentContent);
                commentRepository.Update(pendingComment);
            }
        }

        [WebMethod]
        public void ExportPendingStatusUpdates() {
            var updatesRepository = new NhibernateRepository<EnquiryFixYourStreetStatusUpdate>(Global.SessionFactory.GetCurrentSession());
            var fixYourStreetService = new FixYourStreetService
            {
                FysUrl = ConfigurationManager.AppSettings["FixYourStreetUrl"],
                FysFolder = ConfigurationManager.AppSettings["FixYourStreetApiFolder"],
                FysApiVersion = ConfigurationManager.AppSettings["FixYourStreetApiVersion"]
            };

            var updates = updatesRepository.QueryOver().Where(u => !u.StatusSent).OrderBy(u => u.DateCreated).Asc.List();

            foreach (var fysUpdate in updates) {
                fixYourStreetService.SubmitStatusUpdate(fysUpdate.FixYourStreetId, fysUpdate.Status);
                fysUpdate.StatusSent = true;
                fysUpdate.DateSent = DateTime.Now;
                updatesRepository.Update(fysUpdate);
            }
        }

        private static Dictionary<int, EnquiryCategory> GetCategoryMatchUps() {
            var matchUps = new Dictionary<int, EnquiryCategory>();
            var categoryRepository = new NhibernateRepository<EnquiryCategory>(Global.SessionFactory.GetCurrentSession());
            var configMatchUps = ConfigurationManager.AppSettings["CategoryMatchUps"];
            var matchUpPairings = configMatchUps.Split(',');

            foreach (var matchUpPairing in matchUpPairings) {
                var splitIds = matchUpPairing.Split(':');
                var fysId = int.Parse(splitIds[0]);
                var catId = int.Parse(splitIds[1]);
                matchUps.Add(fysId, categoryRepository.LoadReference(catId));
            }

            return matchUps;
        }

        private static Dictionary<int, User> GetCategoryRefereeMatchUps() {
            var matchUps = new Dictionary<int, User>();
            var configMatchUps = ConfigurationManager.AppSettings["CategoryRefereeMatchUps"];
            if (configMatchUps.Length > 0) {
                var userRepository = new NhibernateRepository<User>(Global.SessionFactory.GetCurrentSession());

                var matchUpPairings = configMatchUps.Split(',');

                foreach (var matchUpPairing in matchUpPairings) {
                    var splitIds = matchUpPairing.Split(':');
                    var fysId = int.Parse(splitIds[0]);
                    var userId = int.Parse(splitIds[1]);
                    matchUps.Add(fysId, userRepository.LoadReference(userId));
                }
            }

            return matchUps;
        }

        private static EnquiryClassification GetDefaultClassification() {
            var classificationRepository = new NhibernateRepository<EnquiryClassification>(Global.SessionFactory.GetCurrentSession());
            var classificationId = int.Parse(ConfigurationManager.AppSettings["DefaultFysClassification"]);
            return classificationRepository.LoadReference(classificationId);
        }

        private static EnquirySource GetDefaultSource() {
            var sourceRepository = new NhibernateRepository<EnquirySource>(Global.SessionFactory.GetCurrentSession());
            var sourceId = int.Parse(ConfigurationManager.AppSettings["FysSourceId"]);
            return sourceRepository.LoadReference(sourceId);
        }

        private static User GetDefaultUser() {
            var userRepository = new NhibernateRepository<User>(Global.SessionFactory.GetCurrentSession());
            var username = ConfigurationManager.AppSettings["AdminUsername"];
            return userRepository.QueryOver().Where(u => u.Username == username).SingleOrDefault();
        }

        private static User GetDefaultSubmitter() {
            var userRepository = new NhibernateRepository<User>(Global.SessionFactory.GetCurrentSession());
            var userId = int.Parse(ConfigurationManager.AppSettings["DefaultFysSubmitter"]);
            return userRepository.GetById(userId);
        }

        private static User GetDefaultReferee() {
            var userRepository = new NhibernateRepository<User>(Global.SessionFactory.GetCurrentSession());
            var userId = int.Parse(ConfigurationManager.AppSettings["DefaultFysReferee"]);
            return userRepository.GetById(userId);
        }

        private static int GetFysCategoryId(Dictionary<int, EnquiryCategory> matchups, int categoryId) {
            foreach (var enquiryCategory in matchups) {
                if (enquiryCategory.Value.Id == categoryId) {
                    return enquiryCategory.Key;
                }
            }
            return 0;
        }
    }
}
